/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2009 - 2012 Luca Mingardi.
 *
 * This file is part of jeeObserver.
 *
 * JeeObserver is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * JeeObserver is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package jeeobserver.server.settings;

import java.io.UnsupportedEncodingException;
import java.util.Properties;
import java.util.logging.Level;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import jeeobserver.server.JeeObserverServerContext;
import jeeobserver.server.JeeObserverServerException;

/**
 * The Class EmailNotification.
 *
 * @author Luca Mingardi
 * @version 4.0
 */
public final class EmailNotification extends Notification {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 40L;

	/** The Constant EMAIL_CONTENT_TYPE_TEXT_PLAIN. */
	public static final String EMAIL_CONTENT_TYPE_TEXT_PLAIN = "text/plain";

	/** The Constant EMAIL_CONTENT_TYPE_TEXT_HTML. */
	public static final String EMAIL_CONTENT_TYPE_TEXT_HTML = "text/html";

	/** The Constant ADDRESS_SEPARATOR. */
	public static final String ADDRESS_SEPARATOR = ",";

	/** The to addresses. */
	private String[] toAddresses;

	/** The cc addresses. */
	private String[] ccAddresses;

	/** The bcc addresses. */
	private String[] bccAddresses;

	/** The content type. */
	private String contentType = EmailNotification.EMAIL_CONTENT_TYPE_TEXT_PLAIN;

	/**
	 * Instantiates a new email notification.
	 *
	 * @param notification the notification
	 */
	public EmailNotification(EmailNotification notification) {

		super(notification);

		this.toAddresses = notification.getToAddresses();
		this.ccAddresses = notification.getCcAddresses();
		this.bccAddresses = notification.getBccAddresses();

		this.contentType = notification.getContentType();
	}

	/**
	 * Instantiates a new email notification.
	 *
	 * @param toAddresses the to addresses
	 * @param subject the subject
	 * @param text the text
	 */
	public EmailNotification(String[] toAddresses, String subject, String text) {
		super(subject, text);

		this.toAddresses = toAddresses;
	}

	/**
	 * Instantiates a new email notification.
	 *
	 * @param toAddresses the to addresses
	 * @param subject the subject
	 * @param text the text
	 */
	public EmailNotification(String toAddresses, String subject, String text) {
		super(subject, text);

		this.toAddresses = toAddresses.split(EmailNotification.ADDRESS_SEPARATOR);
	}

	/**
	 * Instantiates a new email notification.
	 *
	 * @param toAddresses the to addresses
	 * @param ccAddresses the cc addresses
	 * @param bccAddresses the bcc addresses
	 * @param subject the subject
	 * @param text the text
	 * @param contentType the content type
	 */
	public EmailNotification(String[] toAddresses, String[] ccAddresses, String[] bccAddresses, String subject, String text, String contentType) {
		super(subject, text);

		this.toAddresses = toAddresses;
		this.ccAddresses = ccAddresses;
		this.bccAddresses = bccAddresses;

		this.contentType = contentType;
	}

	/**
	 * Gets the to addresses as string.
	 *
	 * @return the to addresses as string
	 */
	public String getToAddressesAsString() {
		String addressesString = "";
		for (int i = 0; i < this.toAddresses.length; i++) {
			addressesString = addressesString + this.toAddresses[i];

			if (i < (this.toAddresses.length - 1)) {
				addressesString = addressesString + EmailNotification.ADDRESS_SEPARATOR;
			}
		}
		return addressesString;
	}

	/**
	 * Gets the cc addresses as string.
	 *
	 * @return the cc addresses as string
	 */
	public String getCcAddressesAsString() {
		String addressesString = "";
		for (int i = 0; i < this.ccAddresses.length; i++) {
			addressesString = this.ccAddresses[i];

			if (i < (this.ccAddresses.length - 1)) {
				addressesString = addressesString + EmailNotification.ADDRESS_SEPARATOR;
			}
		}
		return addressesString;
	}

	/**
	 * Gets the bcc addresses as string.
	 *
	 * @return the bcc addresses as string
	 */
	public String getBccAddressesAsString() {
		String addressesString = "";
		for (int i = 0; i < this.bccAddresses.length; i++) {
			addressesString = this.bccAddresses[i];

			if (i < (this.bccAddresses.length - 1)) {
				addressesString = addressesString + EmailNotification.ADDRESS_SEPARATOR;
			}
		}
		return addressesString;
	}

	/**
	 * Gets the to addresses.
	 *
	 * @return the to addresses
	 */
	public String[] getToAddresses() {
		return this.toAddresses;
	}

	/**
	 * Sets the to addresses.
	 *
	 * @param toAddresses the new to addresses
	 */
	public void setToAddresses(String[] toAddresses) {
		this.toAddresses = toAddresses;
	}

	/**
	 * Gets the cc addresses.
	 *
	 * @return the cc addresses
	 */
	public String[] getCcAddresses() {
		return this.ccAddresses;
	}

	/**
	 * Sets the cc addresses.
	 *
	 * @param ccAddresses the new cc addresses
	 */
	public void setCcAddresses(String[] ccAddresses) {
		this.ccAddresses = ccAddresses;
	}

	/**
	 * Gets the bcc addresses.
	 *
	 * @return the bcc addresses
	 */
	public String[] getBccAddresses() {
		return this.bccAddresses;
	}

	/**
	 * Sets the bcc addresses.
	 *
	 * @param bccAddresses the new bcc addresses
	 */
	public void setBccAddresses(String[] bccAddresses) {
		this.bccAddresses = bccAddresses;
	}

	/**
	 * Gets the content type.
	 *
	 * @return the content type
	 */
	public String getContentType() {
		return this.contentType;
	}

	/**
	 * Sets the content type.
	 *
	 * @param contentType the new content type
	 */
	public void setContentType(String contentType) {
		this.contentType = contentType;
	}

	@Override
	public boolean send() {

		try {
			final Settings settings = JeeObserverServerContext.getInstance().getDatabaseHandler().loadSettings();

			final boolean debug = false;

			if ((settings.getSmtpConnection().getHostName() == null) || settings.getSmtpConnection().getHostName().isEmpty()) {
				JeeObserverServerContext.logger.log(Level.SEVERE, "Unable to send email, SMTP server host is not valid.");
				return false;
			}

			if ((settings.getSmtpConnection().getPort() <= 0)) {
				JeeObserverServerContext.logger.log(Level.SEVERE, "Unable to send email, SMTP server port is not valid.");
				return false;
			}

			// Set the host smtp address
			final Properties properties = new Properties();
			properties.put("mail.smtp.starttls.enable", "true");
			properties.put("mail.smtp.host", settings.getSmtpConnection().getHostName());

			Session session;

			// Check if have to check authentication
			if (settings.getSmtpConnection().isSecurityEnable()) {
				properties.put("mail.smtp.auth", "true");

				final SMTPAuthenticator authenticator = new SMTPAuthenticator(settings.getSmtpConnection().getUsername(), settings.getSmtpConnection().getPassword());

				// session = Session.getDefaultInstance(props, authenticator);
				// Don't use default instance because it remember properties if
				// you change!
				session = Session.getInstance(properties, authenticator);

			} else {
				properties.put("mail.smtp.auth", "false");
				session = Session.getInstance(properties, null);
			}

			session.setDebug(debug);

			// create a message
			final Message msg = new MimeMessage(session);

			// Set the from address
			if ((settings.getSmtpConnection().getFromAddress() != null) && !settings.getSmtpConnection().getFromAddress().isEmpty()) {
				final InternetAddress addressFrom = new InternetAddress(settings.getSmtpConnection().getFromAddress());
				addressFrom.setPersonal(settings.getSmtpConnection().getFromName());
				msg.setFrom(addressFrom);
			}

			// Set the To address
			final InternetAddress[] addressTo = new InternetAddress[this.getToAddresses().length];
			for (int i = 0; i < this.getToAddresses().length; i++) {
				addressTo[i] = new InternetAddress(this.getToAddresses()[i]);
			}

			msg.setRecipients(Message.RecipientType.TO, addressTo);

			// Set the Cc address
			if (this.getCcAddresses() != null) {
				final InternetAddress[] addressCc = new InternetAddress[this.getCcAddresses().length];
				for (int i = 0; i < this.getCcAddresses().length; i++) {
					addressCc[i] = new InternetAddress(this.getCcAddresses()[i]);
				}
				msg.setRecipients(Message.RecipientType.CC, addressCc);
			}

			// Set the Bcc address
			if (this.getBccAddresses() != null) {
				final InternetAddress[] addressBcc = new InternetAddress[this.getBccAddresses().length];
				for (int i = 0; i < this.getBccAddresses().length; i++) {
					addressBcc[i] = new InternetAddress(this.getBccAddresses()[i]);
				}
				msg.setRecipients(Message.RecipientType.BCC, addressBcc);
			}

			// Setting the Subject and Content Type
			msg.setSubject(this.getFilledSubject());
			msg.setContent(this.getFilledText(), this.getContentType());

			Transport.send(msg);

		} catch (final Exception e) {
			JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage(), e);
			return false;
		}

		return true;
	}

	/**
	 * The Class SMTPAuthenticator.
	 *
	 * @author Luca Mingardi
	 * @version 4.0
	 */
	private static class SMTPAuthenticator extends javax.mail.Authenticator {

		/** The username. */
		private final String username;

		/** The password. */
		private final String password;

		/**
		 * Instantiates a new sMTP authenticator.
		 *
		 * @param username the username
		 * @param password the password
		 */
		public SMTPAuthenticator(String username, String password) {
			super();
			this.username = username;
			this.password = password;
		}

		@Override
		public PasswordAuthentication getPasswordAuthentication() {
			return new PasswordAuthentication(this.username, this.password);
		}
	}
}
